/*
 * Copyright 2013-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.opencee.cloud.api.gateway.filter;

import com.alibaba.cloud.dubbo.metadata.RequestMetadata;
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory;
import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory;
import com.opencee.cloud.api.gateway.filter.context.GatewayContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.*;

/**
 * @author Spencer Gibb
 * @author Tim Ysewyn
 */
public class DubboClientFilter implements GlobalFilter, Ordered {

    /**
     * Filter order for {@link DubboClientFilter}.
     */
    private static final Log log = LogFactory.getLog(DubboClientFilter.class);
    private final DubboServiceMetadataRepository repository;

    private final DubboGenericServiceFactory serviceFactory;

    private final DubboGenericServiceExecutionContextFactory contextFactory;

    private final Map<String, Object> dubboTranslatedAttributes = new HashMap<>();

    public DubboClientFilter(DubboServiceMetadataRepository repository,
                             DubboGenericServiceFactory serviceFactory,
                             DubboGenericServiceExecutionContextFactory contextFactory) {
        this.repository = repository;
        this.serviceFactory = serviceFactory;
        this.contextFactory = contextFactory;
        dubboTranslatedAttributes.put("protocol", "dubbo");
        dubboTranslatedAttributes.put("cluster", "failover");
    }

    @Override
    public int getOrder() {
        return 10150 + 100;
    }

    @Override
    @SuppressWarnings("Duplicates")
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
        if (isAlreadyRouted(exchange)
                || !"dubbo".equals(url.getScheme())) {
            return chain.filter(exchange);
        }
        setAlreadyRouted(exchange);
        Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);

        log.debug("DubboClientFilter serverName before: " + route.getMetadata());
        // 初始化 serviceName 的 REST 请求元数据
//        repository.initializeMetadata(serviceName);
//        // 将 HttpServletRequest 转化为 RequestMetadata
//        RequestMetadata clientMetadata = buildRequestMetadata(exchange);
//        DubboRestServiceMetadata dubboRestServiceMetadata = repository.get(serviceName,
//                clientMetadata);
//
//        if (dubboRestServiceMetadata == null) {
//            // if DubboServiceMetadata is not found, executes next
//            throw NotFoundException.create(true,
//                    "DubboServiceMetadata can't be found!");
//        }
//        RestMethodMetadata dubboRestMethodMetadata = dubboRestServiceMetadata
//                .getRestMethodMetadata();
//
//        GenericService genericService = serviceFactory.create(dubboRestServiceMetadata,
//                dubboTranslatedAttributes);
       /* Map<String,Object> metadata = routeDefinition.getMetadata();
        OpenApi api = BeanUtil.mapToBean((Map<?, ?>) metadata.get("api"), OpenApi.class, true);
        OpenApiServer server = BeanUtil.mapToBean((Map<?, ?>) metadata.get("server"), OpenApiServer.class, true);
        ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
        reference.setGroup(serverName);
        reference.setInterface(server.getClassName());
        reference.setVersion(api.getApiVersion());
        // 声明为泛化API
        reference.setGeneric(true);
        reference.setProtocol("dubbo");
        reference.setCluster("failover");
        // 查询泛化API
        GenericService genericService = reference.get();
        // 基础类型及Date、List、Map等不需要转换,直接调用
        Object result = genericService.$invoke(server.getMethodName(), new String[]{"java.lang.String"}, new Object[]{"word"});*/
        //log.debug("DubboClientFilter invoke result:" + result);
        // 用Map表示Pojo参数,如果返回值为Pojo，那么也将自动转换为Map
        //Map<String,Object> person = new HashMap<>();
        //person.put("name","xxx");
        //person.put("sex","2");
        //如果返回pojo,则自动转换为Map
        //Object result = genericService.$invoke(routeDefinition.getServicePath(),new String[]{"com.xxx.Persion"},new Object[]{person});
        return chain.filter(exchange);
    }

    private RequestMetadata buildRequestMetadata(ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        GatewayContext gatewayContext = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);
        // 排除文件上传

        RequestMetadata requestMetadata = new RequestMetadata();
        requestMetadata.setPath(request.getPath().value());
        requestMetadata.setMethod(request.getMethodValue());
        requestMetadata.setParams(gatewayContext.getAllRequestData());
        requestMetadata.setHeaders(request.getHeaders());
        return requestMetadata;
    }


}
